<!DOCTYPE html>
<html>
<head>
  <title>throttle节流</title>
</head>
<body>
<div id='container' style="height:300px;width:100%;background-color:black;color: white;font-size:23px;text-align: center;line-height: 300px;">
  0
</div>
<script type="text/javascript">

  // 参考：https://github.com/mqyqingfeng/Blog/issues/26
  // 节流：一定时间规定只运行一次,例如眨眼睛

  var count = 0;
  var container = document.getElementById('container');
  function getUserAction(e) {
      console.log(e);
      container.innerHTML = count++;
  };
  // 第一版
  function throttle1 (func, wait) {
    var context, args;
    var previous = 0;
    return function() {
        var now = +new Date();
        context = this;
        args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
  }

// 第二版
function throttle2 (func, wait) {
  var timeout;
  var previous = 0;
  return function() {
    context = this;
    args = arguments;
    if (!timeout) {
      timeout = setTimeout(function(){
          timeout = null;
          func.apply(context, args)
      }, wait)
    }
  }
}

// 第三版
function throttle3 (func, wait) {
    var timeout, context, args, result;
    var previous = 0;

    var later = function() {
        previous = +new Date();
        timeout = null;
        func.apply(context, args)
    };

    var throttled = function() {
        var now = +new Date();
        //下次触发 func 剩余的时间
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
         // 如果没有剩余的时间了或者你改了系统时间
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
        } else if (!timeout) {
            timeout = setTimeout(later, remaining);
        }
    };
    return throttled;
}

// 第四版
// options 作为第三个参数
// leading：false 表示禁用第一次执行
// trailing: false 表示禁用停止触发的回调
function throttle4 (func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        func.apply(context, args);
        if (!timeout) context = args = null;
    };

    var throttled = function() {
        var now = new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
        }
    };
    throttled.cancel = function() {
        clearTimeout(timeout);
        previous = 0;
        timeout = null;
    };
    return throttled;
}

  // container.onmousemove = getUserAction; // 原始
  // container.onmousemove = throttle1(getUserAction, 1000);  // 第一版
  container.onmousemove = throttle2(getUserAction, 1000);  // 第二版
  // container.onmousemove = throttle3(getUserAction, 1000);  // 第三版
  // container.onmousemove = throttle4(getUserAction, 1000);  // 第四版


// 所以比较第一版和第二版两个方法：
// 第一种事件会立刻执行，第二种事件会在 n 秒后第一次执行
// 第一种事件停止触发后没有办法再执行事件，第二种事件停止触发后依然会再执行一次事件


// 第4版只有以下几种情况
// container.onmousemove = throttle4(getUserAction, 1000);
// container.onmousemove = throttle4(getUserAction, 1000, {
//     leading: false
// });
// container.onmousemove = throttle4(getUserAction, 1000, {
//     trailing: false
// });
</script>
</body>
</html>
